package com.smsc.headend.task.engine.handler.impl.collection;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.SystemClock;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.smsc.headend.common.enums.DeviceType;
import com.smsc.headend.common.enums.errorcode.TaskHandlerErrorCode;
import com.smsc.headend.common.utils.CosemUtils;
import com.smsc.headend.common.utils.ProtoBufferUtil;
import com.smsc.headend.module.asset.entity.ComEntity;
import com.smsc.headend.module.event.entity.RdEventDcu;
import com.smsc.headend.module.protocol.DeviceData;
import com.smsc.headend.module.protocol.cosem.bo.CosemData;
import com.smsc.headend.module.report.entity.LogScheduleTaskDevice;
import com.smsc.headend.module.task.consts.TaskKafkaTopic;
import com.smsc.headend.module.task.dto.AtomicTask;
import com.smsc.headend.module.task.dto.Task;
import com.smsc.headend.module.task.dto.TaskEventData;
import com.smsc.headend.module.task.enums.TaskType;
import com.smsc.headend.module.task.proto.TaskEventDataProto;
import com.smsc.headend.task.engine.dao.TaskDAO;
import com.smsc.headend.task.engine.exception.UDISTaskHandlerException;
import com.smsc.headend.task.engine.handler.TaskHandler;
import com.smsc.headend.task.engine.service.CollTermTaskPlanService;
import com.smsc.headend.task.engine.service.CosemXmlService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.asset.AssetService;
import com.smsc.headend.task.engine.service.push.EventService;
import com.smsc.headend.task.engine.service.task.LogScheduleTaskDeviceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;

import java.util.Date;
import java.util.List;
import java.util.Map;

@Slf4j
public class ReadDcuEventProfileHandler implements TaskHandler {

    @Autowired
    TaskDAO taskDAO;

    @Autowired
    CosemXmlService cosemXmlService;

    @Autowired
    KafkaTemplate kafkaTemplate;

    @Autowired
    EventService eventService;

    @Autowired
    AssetService assetService;

    @Autowired
    CollTermTaskPlanService collTermTaskPlanService;
    @Autowired
    LogScheduleTaskDeviceService logScheduleTaskDeviceService;

    @Override
    public int handle(Task task, AtomicTask atomicTask, DeviceData deviceData, String actionResult) throws UDISTaskHandlerException {
        log.debug("result={}, data={}", actionResult, deviceData.toString());
        if (!(deviceData instanceof CosemData)) {
            throw new UDISTaskHandlerException(TaskHandlerErrorCode.DEVICE_DATA_TYPE_NOT_SUPPORT.toString());
        }

        Map<String, Object> param = this.getParameterMap(task, atomicTask);
        Long lbDataItemId = Long.valueOf(String.valueOf(param.get("dataItemId")));
        ComEntity com = assetService.getComById(task.getComId());
        CosemData cosemData = (CosemData) deviceData;
        Long tvUpdate = SystemClock.now() / 1000;
        List<RdEventDcu> allEvent = CollUtil.newArrayList();
        if (CollUtil.isNotEmpty(cosemData.getChild())) {
            for (CosemData structData : cosemData.getChild()) {
                if (structData.getChild().size() != 2) {
                    log.error("the event data has wrong format");
                    continue;
                }
                RdEventDcu rdEventDcu = new RdEventDcu();
                rdEventDcu.setLogSeq(UUID.fastUUID().toString());
                rdEventDcu.setDcuId(com.getDeviceId());
                rdEventDcu.setReceiveType(2);
                rdEventDcu.setTvUpdate(tvUpdate);
                String dateStr = (String) cosemXmlService.getData(structData.getChild().get(0).getType(), structData.getChild().get(0).getValue());
                Date date = CosemUtils.parseOctStringDataTime(dateStr);
                rdEventDcu.setTv(date.getTime() / 1000);
                Integer eventCode = Convert.toInt(cosemXmlService.getData(structData.getChild().get(1).getType(), structData.getChild().get(1).getValue()));
                Integer eventType = eventService.getTaskEventType(task, eventCode, lbDataItemId, DeviceType.DCU.getId());
                rdEventDcu.setEventType(Convert.toLong(eventType));
                rdEventDcu.setEventCode(eventCode);
                if (null != eventType) {
                    rdEventDcu.setEventName(eventService.getEventName(Convert.toLong(eventType)));
                } else {
                    rdEventDcu.setEventName("not config");
                    log.error("not found the eventType in db：eventCode={},lbDataItemId={},deviceType={},comId={}", eventCode, lbDataItemId, DeviceType.DCU.getId(), task.getComId());
                }
                allEvent.add(rdEventDcu);
            }
        }

        TaskEventData readData = new TaskEventData();
        readData.setRdEventDcu(allEvent);
        readData.setLbDataItemId(lbDataItemId);
        readData.setTaskNo(task.getTaskNo());
        readData.setIsODR(task.getIsODR());
        readData.setDeviceId(com.getDeviceId());
        readData.setDeviceType(DeviceType.DCU.getId());
        if (allEvent.size() > 0) {
            kafkaTemplate.send(TaskKafkaTopic.DEVICE_EVENT_TRANSFER, ProtoBufferUtil.toProtoBuffer(readData, TaskEventDataProto.TaskEventData.class).toByteArray());
            if (TaskType.ScheduleRead_LogBook.toString().equalsIgnoreCase(task.getTaskType())) {
                logScheduleTaskDeviceService.sendMessage(task, LogScheduleTaskDevice.StatusEnum.Success.getCode(), LogScheduleTaskDevice.StatusDescEnum.CollectedSuccess.getCode());
            }
        } else {
            if (TaskType.ScheduleRead_LogBook.toString().equalsIgnoreCase(task.getTaskType())) {
                logScheduleTaskDeviceService.sendMessage(task, LogScheduleTaskDevice.StatusEnum.Failed.getCode(), LogScheduleTaskDevice.StatusDescEnum.EmptyData.getCode());
            }
        }

        if (task.getIsODR()) {
            taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), lbDataItemId.toString(), JSONUtil.toJsonStr(allEvent), Long.valueOf(1 * 60 * 60), true);
        }

        if (TaskType.ScheduleRead_LogBook.toString().equalsIgnoreCase(task.getTaskType())) {
            collTermTaskPlanService.saveTermCollectProgress(SystemClock.now() / 1000, com.getDeviceId(), lbDataItemId);
        }
        /*Long taskFinalEndTv = Long.parseLong(String.valueOf(param.get("profileEndTime")));
        AtomicTaskState atomicTaskState = taskDAO.hashGetAtomicTaskState(atomicTask.getAtomicTaskNo());
        if (atomicTaskState.getCollectingEndTv() < taskFinalEndTv) {
            atomicTaskState.setCollectedEndTv(atomicTaskState.getCollectingEndTv());
            taskDAO.hashSetAtomicTaskState(atomicTask.getAtomicTaskNo(), task, atomicTaskState.getRetryTimes(), atomicTaskState);
            return 0;
        }*/

        return 1;
    }

    @Override
    public int handleFailure(Task task, AtomicTask atomicTask, String message) {
        log.info("ReadDcuEventProfile error {}, ", message);
        if (task.getIsODR()) {
            Map<String, Object> param = getParameterMap(task, atomicTask);
            Long lbDataItemId = Long.valueOf(String.valueOf(param.get("dataItemId")));
            // key 回曲线的dataItemId给web
            taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(lbDataItemId), message, 3600l, false);
        }
        if (StrUtil.equalsIgnoreCase(task.getTaskType(), TaskType.ScheduleRead_LogBook.name())) {
            logScheduleTaskDeviceService.sendMessage(task, LogScheduleTaskDevice.StatusEnum.Failed.getCode(), LogScheduleTaskDevice.StatusDescEnum.DecodeDataFailed.getCode());
        }
        return -1;
    }
}
